﻿@page "/chat"
@using Microsoft.AspNetCore.SignalR
@using Microsoft.AspNetCore.SignalR.Client
@using Microsoft.AspNetCore.Http.Connections;
@using System.Web;
@inject NavigationManager NavigationManager
@inject IJSRuntime JSRuntime

<h1>Chat Room</h1>
<button id="connectButton" @onclick="Connect">Connect SignalR</button>
<button id="subscribeButton" @onclick="Subscribe">Subscribe to server messages</button>
<button id="sendMessageButton" @onclick="SignalRPassMessages">Send message from query</button>
<button id="exitProgramButton" @onclick="SendExitSignal">Send exit signal to server</button>
<button id="disconnectButton" @onclick="DisposeHubConnection">Disconnect SignalR</button>
<div>
    @foreach (var chatMessage in chatMessages)
    {
        <p>@chatMessage</p>
    }
</div>

@code {
    private string _hubUrl = string.Empty;
    private HubConnection? _hubConnection;
    private string message = string.Empty;
    private string transport = string.Empty;
    private List<string> chatMessages = new List<string>();
    private string wrongQueryError = "Query string with parameters 'message' and 'transport' are required";

    // remove when https://github.com/dotnet/runtime/issues/96546 is fixed
    // log that rendering is about to start in case we hit the issue before OnAfterRender is called
    protected override bool ShouldRender()
    {
        bool shouldRender = base.ShouldRender();
        Helper.TestOutputWriteLine($"ShouldRender = {shouldRender}");
        return shouldRender;
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            Helper.TestOutputWriteLine($"OnAfterRender on CurrentManagedThreadId={Environment.CurrentManagedThreadId}");
            GetQueryParameters();
        }
        base.OnAfterRender(firstRender);
    }

    private void GetQueryParameters()
    {
        var uri = new Uri(NavigationManager.Uri);
        if (string.IsNullOrEmpty(uri.Query))
        {
            throw new Exception(wrongQueryError);
        }
        var parameters = HttpUtility.ParseQueryString(uri.Query);
        if (parameters == null)
        {
            throw new Exception(wrongQueryError);
        }
        transport = Helper.GetValue(parameters, "transport");
        message = $"{transport} {Helper.GetValue(parameters, "message")}" ;
        Helper.TestOutputWriteLine($"Finished GetQueryParameters on CurrentManagedThreadId={Environment.CurrentManagedThreadId}.");
    }

    private async Task Connect()
    {
        _hubUrl = NavigationManager.BaseUri + "chathub";
        HttpTransportType httpTransportType = Helper.StringToTransportType(transport);
        _hubConnection = new HubConnectionBuilder()
            .WithUrl(_hubUrl, options =>
                {
                    options.Transports = httpTransportType;
                })
            .Build();

        await _hubConnection.StartAsync();
        Helper.TestOutputWriteLine($"SignalR connected by CurrentManagedThreadId={Environment.CurrentManagedThreadId}");
    }

    private void Subscribe()
    {
        _hubConnection.On<string>("ReceiveMessage", (message) =>
        {
            Helper.TestOutputWriteLine($"Message = [{message}]. ReceiveMessage from server on CurrentManagedThreadId={Environment.CurrentManagedThreadId}");
            chatMessages.Add(message);
        });
        Helper.TestOutputWriteLine($"Subscribed to ReceiveMessage by CurrentManagedThreadId={Environment.CurrentManagedThreadId}");
    }

    private async Task SignalRPassMessages() =>
        await Task.Run(async () =>
            {
                await _hubConnection.SendAsync( "SendMessage", message, Environment.CurrentManagedThreadId);
                Helper.TestOutputWriteLine($"SignalRPassMessages was sent by CurrentManagedThreadId={Environment.CurrentManagedThreadId}");
            });

    private async Task SendExitSignal()
    {
        await DisposeHubConnection();
        // exit the client
        Helper.TestOutputWriteLine($"SendExitSignal by CurrentManagedThreadId={Environment.CurrentManagedThreadId}");
        await JSRuntime.InvokeVoidAsync("eval", "setTimeout(() => { getDotnetRuntime(0).exit(0); }, 50);");
    }

    private async Task DisposeHubConnection()
    {
        if (_hubConnection != null)
        {
            _hubConnection.Remove("ReceiveMessage");
            await _hubConnection.DisposeAsync();
            _hubConnection = null;
        }
        Helper.TestOutputWriteLine($"SignalR disconnected by CurrentManagedThreadId={Environment.CurrentManagedThreadId}");
    }
}
